package com.furtherstar.auth.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.furtherstar.auth.controller.dto.AppResourceTree;
import com.furtherstar.auth.dao.enums.AppResourceType;
import com.furtherstar.auth.dao.enums.Disabled;
import com.furtherstar.auth.dao.mapper.AppResourceMapper;
import com.furtherstar.auth.dao.mapper.AppRoleResourceMapper;
import com.furtherstar.auth.dao.model.AppResource;
import com.furtherstar.auth.dao.model.AppResourceExample;
import com.furtherstar.auth.dao.model.AppRoleResourceExample;
import com.furtherstar.auth.service.AppResourceService;
import com.yummy.convention.collection.TreeUtils;
import com.yummy.convention.exception.AssertUtil;
import com.yummy.convention.lang.IDGenerator;
import com.yummy.security.User;
import com.yummy.web.context.RequestContext;

@Service
public class AppResourceServiceImpl implements AppResourceService{
	
	@Autowired
	private AppResourceMapper appResourceMapper;
	@Autowired
	private AppRoleResourceMapper appRoleResourceMapper;

	@Override
	public Long add(AppResource resource) {
		checkIllegal(resource);
		createMark(resource);
		appResourceMapper.insert(resource);
		return resource.getId();
	}

	private void createMark(AppResource resource) {
		resource.setId(IDGenerator.getId());
		resource.setDisabled(Disabled.normal.ordinal());
		if(resource.getSort() == null) {
			resource.setSort(0);
		}
		User user = RequestContext.getCurrentUser();
		resource.setLmNickname(user.getNickname());
		resource.setLmTime(new Date());
		resource.setLmUserid((Long) user.getUserid());
	}

	private void checkIllegal(AppResource resource) {
		Integer type = resource.getType();
		Long parentId = resource.getId();
		if(type.equals(AppResourceType.nav.ordinal())) {
			AssertUtil.isTrue(parentId == null,"导航栏应为根节点");
		}
		if(parentId == null) {
			AssertUtil.isTrue(type.equals(AppResourceType.nav.ordinal()) 
					|| type.equals(AppResourceType.api.ordinal()),"根节点应为导航栏或接口");
		}
		AppResource parent = appResourceMapper.selectByPrimaryKey(parentId);
		AssertUtil.notNull(parent,"父节点不存在");
		if(type.equals(AppResourceType.button.ordinal())) {
			AssertUtil.isTrue(parent.getType().equals(AppResourceType.page.ordinal()),"按钮父节点应为页面");
		}
		AssertUtil.isTrue(!(parent.getType().equals(AppResourceType.button.ordinal())
				|| parent.getType().equals(AppResourceType.api.ordinal())),"按钮和接口不可添加子节点");
		if(type.equals(AppResourceType.page.ordinal())) {
			AssertUtil.isTrue(parent.getType().equals(AppResourceType.menu.ordinal())
					|| parent.getType().equals(AppResourceType.nav.ordinal()),"页面不可添加页面");
		}
	}

	@Override
	public Long update(AppResource resource) {
		AppResource old = appResourceMapper.selectByPrimaryKey(resource.getId());
		AssertUtil.notNull(old,"找不到记录");
		resource.setAppname(old.getAppname());
		resource.setParentId(old.getParentId());
		resource.setType(resource.getType() == null ? old.getType() : resource.getType());
		checkIllegal(resource);
		optMark(resource);
		appResourceMapper.updateByPrimaryKeySelective(resource);
		return resource.getId();
	}

	private void optMark(AppResource resource) {
		User user = RequestContext.getCurrentUser();
		resource.setLmNickname(user.getNickname());
		resource.setLmTime(new Date());
		resource.setLmUserid((Long) user.getUserid());
	}

	@Override
	public Long enable(Long resourceId) {
		AppResource resource = new AppResource();
		resource.setId(resourceId);
		resource.setDisabled(Disabled.normal.ordinal());
		optMark(resource);
		int row = appResourceMapper.updateByPrimaryKeySelective(resource);
		AssertUtil.isTrue(row == 1,"找不到记录");
		return resourceId;
	}

	@Override
	public Long disable(Long resourceId) {
		AppResource resource = new AppResource();
		resource.setId(resourceId);
		resource.setDisabled(Disabled.disabled.ordinal());
		optMark(resource);
		int row = appResourceMapper.updateByPrimaryKeySelective(resource);
		AssertUtil.isTrue(row == 1,"找不到记录");
		return resourceId;
	}

	@Override
	@Transactional
	public Boolean delete(Long resourceId) {
		AssertUtil.isTrue(canDelete(resourceId),"有子级资源不能删除");
		int row = appResourceMapper.deleteByPrimaryKey(resourceId);
		AssertUtil.isTrue(row == 1,"找不到记录");
		deleteRelated(resourceId);
		return true;
	}

	private void deleteRelated(Long resourceId) {
		AppRoleResourceExample example = new AppRoleResourceExample();
		example.createCriteria().andResourceIdEqualTo(resourceId);
		appRoleResourceMapper.deleteByExample(example);
	}

	private boolean canDelete(Long resourceId) {
		AppResourceExample example = new AppResourceExample();
		example.createCriteria().andParentIdEqualTo(resourceId);
		return appResourceMapper.countByExample(example) == 0;
	}

	@Override
	public List<AppResourceTree> resourcesTree(String appname) {
		List<AppResource> list = getAppResourcesByApp(appname);
		if(CollectionUtils.isEmpty(list)) {
			return Collections.emptyList();
		}
		List<AppResourceTree> treeList = toTree(list);
		return TreeUtils.toTree(treeList, "id", "parentId", "sort", "children", AppResourceTree.class);
	}

	private List<AppResourceTree> toTree(List<AppResource> resources) {
		List<AppResourceTree> trees = new ArrayList<>();
		for(AppResource r : resources) {
			trees.add(toTree(r));
		}
		return trees;
	}

	private AppResourceTree toTree(AppResource r) {
		AppResourceTree t = new AppResourceTree();
		BeanUtils.copyProperties(r, t);
		return t;
	}

	private List<AppResource> getAppResourcesByApp(String appname) {
		AppResourceExample example = new AppResourceExample();
		example.createCriteria().andAppnameEqualTo(appname);
		return appResourceMapper.selectByExample(example);
	}

}
